/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <Winsock2.h>
#include <ws2tcpip.h>

#include "PacketDefinitions.h"
#include "PacketDefinitions6.h"

enum MultiCastAddrType
{
	__mcatUnknown,
	__mcatAllNodes_NodeLocal,
	__mcatAllNodes_LinkLocal,
	__mcatAllRouters_NodeLocal,
	__mcatAllRouters_LinkLocal,
	__mcatAllRouters_SiteLocal,
	__mcatUserSpecified
};

class PacketBuilder6
{
private:
	BYTE* packet;
	int packSize;
	IPv6PseudoHeader pseudoHeader;

	BYTE routerMulticastMAC[6];
	in_addr6 unspecifiedAddress;
	in_addr6 allRouterMulticastAddress;

	/*
	/// Builds a custom IPv6 Header
		\param[out] destIn        Destination - The result is written here
		\param[in]  srcAddr       Source IPv6 Address
		\param[in]  dstAddr       Destination IPv6 Address
		\param[in]  bTrafficClass Traffic Class
		\param[in]  dwFlowLabel   Flow Label (only the least 20 bits !)
		\param[in]  wPayloadLen   Payload Length
		\param[in]  bNextHeader   Next Header
		\param[in]  bHopLimit     Hop Limit
	*/
	bool BuildIPHeader(
				BYTE* destIn,
				in_addr6* srcAddr, in_addr6* dstAddr,
				BYTE bTrafficClass, DWORD dwFlowLabel,
				WORD wPayloadLen, BYTE bNextHeader,
				BYTE bHopLimit);

	/// Computes checksum
	USHORT ComputeCheckSum(USHORT *buffer, int size);

public:
	PacketBuilder6(void);
	~PacketBuilder6(void);

	bool AddEthernetHeaderRouterMulticast(BYTE srcMACIn[6]);
	bool AddEthernetHeaderForIPMulticast(BYTE srcMACIn[6], in_addr6*);
	bool AddEthernetHeaderForIPNS(BYTE srcMACIn[6], in_addr6*);
	bool AddEthernetHeader(BYTE srcMACIn[6], BYTE dstMACIn[6]);

	bool HostMulticastFromIP(in_addr6*);

	bool GetIPv6MulticastAddress(MultiCastAddrType, in_addr6*);

	bool IPv6AddressIsAllNodesLinkLocal(in_addr6*);

	BYTE* GetPacket(void);
	DWORD GetPacketSize(void);

	bool BuildPacketICMPEcho(
			in_addr6* srcAddr, in_addr6* dstAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,
				
			bool request,				///< request or reply ?
			WORD wId,					///< ICMPv6 Id
			WORD wSeq,					///< ICMPv6 Sequence

			BYTE* bpData,				///< data
			DWORD dwDataLen				///< length of data
		);

	bool BuildPacketICMPRouterSolicitation(
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit
		);

	bool BuildPacketICMPRouterSolicitation(
			in_addr6* srcAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,

			BYTE* options,
			DWORD optLen
		);

	bool BuildPacketICMPAddrDetection(
			in_addr6* reqAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit
		);

	bool BuildPacketICMPNeighborSolicitation(
			in_addr6* srcAddr,
			in_addr6* dstAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,

			BYTE* options,
			DWORD optLen
		);

	bool BuildPacketICMPNeighborAdvertisment(
			in_addr6* srcAddr,
			in_addr6* dstAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,

			DWORD dwNaFlags,

			BYTE* options,
			DWORD optLen
		);

	bool BuildPacketICMPMLDQuery(
			in_addr6* srcAddr, in_addr6* dstAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,

			WORD maximumResponseDelay
		);

	bool BuildPacketICMPMLDResponse(
			in_addr6* srcAddr, in_addr6* mcastAddr,
			BYTE bTrafficClass, DWORD dwFlowLabel,
			BYTE bHopLimit,

			WORD maximumResponseDelay
		);

/* ---------------------- */
	bool BuildPacketEmptyIPv6Proto(
			in_addr6* srcAddr,			///< source address
			in_addr6* dstAddr,			///< destination address
			BYTE      bTrafficClass,	///< trafic class
			DWORD     dwFlowLabel,		///< flow label
			BYTE      bHopLimit,		///< hop limit
			BYTE      bNextHeader		///< next header
		);

/* ---------------------- */
	bool BuildPacketTCP(
			in_addr6* srcAddr,		///< source address
			in_addr6* dstAddr,		///< destination address

			BYTE  bTrafficClass,	///< trafic class
			DWORD dwFlowLabel,		///< flow label
			BYTE  bHopLimit,		///< hop limit

			WORD wSP, WORD wDP,		///< source and destination port

			DWORD dwSeq,			///< sequence
			DWORD dwAck,			///< acknowledge
			BYTE bFlags,			///< tcp flags
			WORD wWindow,			///< window
			WORD wUrgent,			///< urgent pointer

			BYTE* bpOpt,			///< options
			DWORD dwOptLen,			///< length of options

			BYTE* bpData,			///< data
			DWORD dwDataLen			///< length of data
		);

/* ---------------------- */
	bool BuildPacketUDP(
			in_addr6* srcAddr,		///< source address
			in_addr6* dstAddr,		///< destination address

			BYTE  bTrafficClass,	///< trafic class
			DWORD dwFlowLabel,		///< flow label
			BYTE  bHopLimit,		///< hop limit

			WORD wSP, WORD wDP,		///< source and destination port

			BYTE* bpData,			///< data
			DWORD dwDataLen			///< length of data
		);
};
